local file, io, type =
      file, io, type

module('apr.std.file')

--- Stream strings between two file-like objects, reading from one in chunks of chunk_size and writing them to the other
-- @param to a file-like object that will "write" results streamed from "from"
-- @param from a file-like object that will be "read" from
-- @param chunk_size optional override for the size of each chunk in bytes, defaults to 8KB
-- @param max optional setting for the maximum number of bytes to stream in total, defaults to streaming until nil is received from the read call
-- @return the number of bytes that were streamed between the two objects
function stream(to, from, chunk_size, max)
    local streamed = 0
    chunk_size = chunk_size or 8192
    if not isfilelike(to) then error("Must stream to file-like object, got " .. to) end
    if not isfilelike(from) then error("Must stream from file-like object, got " .. from) end
    
    repeat
        local chunk
        if max ~= nil then
            chunk = from:read(math.min(chunk_size, max - streamed))
        else
            chunk = from:read(chunk_size)
        end
        
        if chunk ~= nil then
            to:write(chunk)
            streamed = streamed + chunk:len()
        end
    until chunk == nil or (max ~= nil and streamed >= max)
    
    return streamed
end

--- Any object is considered "file-like" if it contains both a read and write function
-- @param test some object to test for file behavior
-- @return true if it's a file-like table object or false if not
function isfilelike(test)
    return (io.type(test) == 'file' or (type(test) == 'table' and type(test.read) == 'function' and type(test.write) == 'function'))
end
